package com.adroiti.texasholdem.engine;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import com.adroiti.texasholdem.Combination;
import com.adroiti.texasholdem.Deck;
import com.adroiti.texasholdem.Engine;
import com.adroiti.texasholdem.Hand;
import com.adroiti.texasholdem.Player;
import com.adroiti.texasholdem.Table;
import com.adroiti.texasholdem.engine.combinations.SimpleCombinationFactory;

public class SimpleEngine implements Engine {

	public static class ReverseCombinations implements Comparator<Combination> {

		@Override
		public int compare(Combination o1, Combination o2) {
			if (o1.getCombinationRank() > o2.getCombinationRank()) {
				return -1;
			} else if (o1.getCombinationRank() < o2.getCombinationRank()) {
				return 1;
			} else
				return 0;
		}

	}

	private Set<Combination> combinations = new TreeSet<Combination>(
			new ReverseCombinations());
	private List<Player> players = new LinkedList<Player>();
	private Deck deck;
	private Table table;

	public SimpleEngine() {

		/**
		 * No IoC here :(
		 */

		CombinationFactory comf = new SimpleCombinationFactory();
		addCombination(comf.getCombination("Flush"));
		addCombination(comf.getCombination("FourOfKind"));
		addCombination(comf.getCombination("FullHouse"));
		addCombination(comf.getCombination("High"));
		addCombination(comf.getCombination("Pair"));
		addCombination(comf.getCombination("RoyalFlush"));
		addCombination(comf.getCombination("Straight"));
		addCombination(comf.getCombination("StraightFlush"));
		addCombination(comf.getCombination("ThreeOfKind"));
		addCombination(comf.getCombination("TwoPair"));

		this.deck = new HoldemDeck();
		this.table = new SimpleTable();

	}

	public void runGame(int playersNum) {

		/**
		 * Create players
		 */
		for (int i = 0; i < playersNum; i++) {
			Hand hand = new PlayerHand(table);
			players.add(new PokerPlayer(hand));
		}

		/**
		 * Distribute cards
		 */

		for (int i = 0; i < 2; i++)
			for (Player player : getPlayers()) {
				player.addCard(deck.fetchCard());
			}

		for (int i = 0; i < 5; i++) {
			table.addCard(deck.fetchCard());
		}

		/**
		 * Set combinations
		 */
		for (Player player : getPlayers()) {
			setPlayerCombination(player);
		}

		Collections.sort(players);

		int num = 1;
		for (Player player : getPlayers()) {
			player.setPlace(num++);
		}

	}

	private void addCombination(Combination combination) {
		combinations.add(combination);
	}

	public Set<Combination> getCombinations() {
		return combinations;
	}

	public List<Player> getPlayers() {
		return players;
	}

	public Deck getDeck() {
		return deck;
	}

	private void setPlayerCombination(Player player) {
		for (Combination combination : getCombinations()) {
			if (combination.getRank(player.getHand().getCards(),
					table.getCards()) > 0) {
				player.getHand().setCombination(combination);
				break;
			}
		}
	}
	
	protected void setPlayers(List<Player> players){
		this.players = players;
	}

}
